#ifndef ___fat32_transaccionB3_escribir_archivo

#define ___fat32_transaccionB3_escribir_archivo 1

#include "f32_mto.c"

#include "f32_st01.c"
#include "f32_st02.c"
#include "f32_st11.c"
#include "f32_st15.c"
#include "f32_st19.c"

struct fat32trB3_errores {
  FAT32_B3_DESCRIPTOR_NO_VALIDO = 1,
  FAT32_B3_NO_PERMITIDO = 2,
  FAT32_B3_DISCO_LLENO = 3,
  FAT32_B3_ESCRITURA_MAS_ALLA_DE_FIN_DE_ARCHIVO = 4
};

struct fat32trB3_datos_entrada {
  unsigned int remitente;
  unsigned long long descriptor;
  unsigned long inicio;
  unsigned long cantidad;
  void * datos;
};

struct fat32trB3_datos_internos {
  unsigned int remitenteMensaje;
  unsigned long long descriptor;
  unsigned long posicionInicial;
  unsigned long cantidadDatos;
  void * datosNuevos;
  void * datosInternos;
  signed short errorDevuelto;
  unsigned int conexion;
  fat32_apertura_archivo datosApertura;
  fat32_lista_bloques_para_escribir * lbpe1;
  fat32_lista_bloques_para_escribir * lbpe2;
  fat32_lista_bloques_para_escribir * lbpeF;
  unsigned char conectado;
};

void fat32tr_escribir_archivo(unsigned int, unsigned long long, unsigned long, unsigned long, void *);
int fat32ctr_escribir_archivo(FAT32_PARAMS_CREACION_TRANSACCION);
int fat32etr_escribir_archivo(FAT32_PARAMS_TRANSACCION);

void fat32tr_escribir_archivo (unsigned int remitente, unsigned long long descriptor, unsigned long inicio, unsigned long cantidad,
                                                                                                                void * datosNuevos) {
  struct fat32trB3_datos_entrada datos;
  datos.remitente = remitente;
  datos.descriptor = descriptor;
  datos.inicio = inicio;
  datos.cantidad = cantidad;
  datos.datos = malloc(cantidad);
  memcpy(datos.datos, datosNuevos, cantidad);
  fat32_crear_transaccion(&fat32ctr_escribir_archivo, &datos, sizeof datos);
}

int fat32ctr_escribir_archivo (FAT32_PARAMS_CREACION_TRANSACCION) {
  struct fat32trB3_datos_entrada * de = datosIniciales;
  struct fat32trB3_datos_internos * di = malloc(sizeof(struct fat32trB3_datos_internos));
  di -> remitenteMensaje = de -> remitenteMensaje;
  di -> posicionInicial = de -> inicio;
  di -> cantidadDatos = de -> cantidad;
  di -> datosNuevos = de -> datos;
  di -> descriptor = de -> descriptor;
  *datos = di;
  *handler = &fat32etr_escribir_archivo;
  return 0xE100;
}

int fat32etr_escribir_archivo (FAT32_PARAMS_TRANSACCION) {
  unsigned char estado1;
  int estado2;
  estado2 = estado >> 8;
  estado1 = estado & 255;
  struct fat32trB3_datos_internos * datosT = *datos;
  switch (estado2) {
  case 0x01:
    estado1 = fat32st_obtener_conexion(estado1, numeroTransaccion, &(datosT -> conexion), resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> conectado = 1;
      estado2 = 0xE1;
      estado1 = 1;
    }
    break;
  case 0x02:
    estado1 = fat32st_cambiar_tamano_asignacion_archivo(estado1, numeroTransaccion, (datosT -> datosApertura).clusterInicialPadre,
                                                        (datosT -> datosApertura).numeroEntrada,
                                                        (datosT -> posicionInicial) + (datosT -> cantidadDatos), &(datosT -> datosInternos),
                                                        resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> lbpe1 = datosT -> datosInternos;
      estado2 = 0xE1;
      if((datosT -> datosApertura).tamano) 
        estado1 = 2;
      else
        estado1 = 6;
    }
    break;
  case 0x03:
    estado1 = fat32st_escribir_datos_en_archivo(estado1, numeroTransaccion, (datosT -> datosApertura).clusterInicial,
                                                datosT -> posicionInicial, datosT -> cantidadDatos, datosT -> datosNuevos,
                                                &(datosT -> datosInternos), resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> lbpe2 = datosT -> datosInternos;
      estado2 = 0xE1;
      estado1 = 3;
    }
    break;
  case 0x04:
    estado1 = fat32st_ejecutar_lista_bloques_para_escribir(estado1, numeroTransaccion, datosT -> lbpeF, &(datosT -> datosInternos),
                                                                                                resultadoOperacion, datosOperacion);
    if (!estado1) {
      estado2 = 0xE1;
      estado1 = 4;
    }
    break;
  case 0x05:
    estado1 = fat32st_liberar_conexion(estado1, numeroTransaccion);
    if (!estado1) {
      estado1 = 5;
      estado2 = 0xE1;
    }
    break;
  case 0xE1:
    switch (estado1) {
    case 0:
      datosT -> lbpe1 = datosT -> lbpe2 = datosT -> lbpeF = NULL;
      datosT -> conectado = 0;
      datosT -> datosApertura = fat32_obtener_apertura(datosT -> descriptor);
      if (!(datosT -> datosApertura).descriptor) {
        datosT -> errorDevuelto = FAT32_B3_DESCRIPTOR_NO_VALIDO;
        estado1 = 4;
      } else if (!(datosT -> datosApertura).modo) {
        datosT -> errorDevuelto = FAT32_B3_NO_PERMITIDO;
        estado1 = 4;
      } else if ((datosT -> posicionInicial) > ((datosT -> datosApertura).tamano)) {
        datosT -> errorDevuelto = FAT32_B3_ESCRITURA_MAS_ALLA_DE_FIN_DE_ARCHIVO;
        estado1 = 4;
      } else {
        datosT -> errorDevuelto = -1;
        estado2 = 0x01;
      }
      break;
    case 1:
      estado1 = 0;
      if (((datosT -> posicionInicial) + (datosT -> cantidadDatos)) > ((datosT -> datosApertura).tamano))
        estado2 = 0x02;
      else
        estado2 = 0x03;
      break;
    case 2:
      if (!(datosT -> lbpe1)) {
        datosT -> errorDevuelto = FAT32_B3_DISCO_LLENO;
        estado1 = 4;
      } else {
        estado2 = 0x03;
        estado1 = 0;
      }
      break;
    case 3:
      if (!(datosT -> lbpe1)) {
        datosT -> lbpeF = datosT -> lbpe2;
        datosT -> lbpe2 = NULL;
      } else {
        datosT -> lbpeF = malloc(sizeof(fat32_lista_bloques_para_escribir));
        fat32_combinar_listas_bloques_para_escribir(datosT -> lbpeF, datosT -> lbpe1, datosT -> lbpe2, NULL);
      }
      estado2 = 0x04;
      estado1 = 0;
      break;
    case 4:
      if (datosT -> lbpe1) free(datosT -> lbpe1);
      if (datosT -> lbpe2) free(datosT -> lbpe2);
      if (datosT -> lbpeF) free(datosT -> lbpeF);
      free(datosT -> datosNuevos);
      if ((datosT -> errorDevuelto) != -1)
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_NO_ESCRIBIO_ARCHIVO, datosT -> descriptor,
                                                                                            (int) (datosT -> errorDevuelto));
      else
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_ESCRIBIO_EN_ARCHIVO, datosT -> descriptor,
                                                                                                    datosT -> cantidadDatos);
      if (datosT -> conectado) {
        estado2 = 0x05;
        estado1 = 0;
      } else
        estado1 = 5;
      break;
    case 5:
      free(datosT);
      estado1 = 0;
      estado2 = 0;
      break;
    case 6:
      46;
      unsigned long bloque;
      char mascara[256];
      char datos[2048];
      unsigned short posicion;
      char numeros[4];
      unsigned long c1, c3;
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_SIGUIENTE_BLOQUE, datosT -> lbpe1, 0, 0, 0, &bloque);
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_MASCARA_BLOQUE, datosT -> lbpe1, bloque, 0, 0, mascara);
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_DATOS_BLOQUE, datosT -> lbpe1, bloque, 0, 0, datos);
      for (posicion = 0; posicion < 64; posicion ++) {
        c1 = 0;
        for (c3 = 0; c3 < 4; c3 ++) c1 |= mascara[4 * posicion + c3];
        if (c1) break;
      }
      if (posicion < 64) {
        numeros[0] = datos[32 * posicion + 26];
        numeros[1] = datos[32 * posicion + 27];
        numeros[2] = datos[32 * posicion + 20];
        numeros[3] = datos[32 * posicion + 21];
        c1 = fb_convertir_de_little_endian(numeros, 32);
        (datosT -> datosApertura).clusterInicial = c1;
        fat32_modificar_apertura(datosT -> datosApertura);
      }
      estado1 = 2;
      break;
    }
    break;
  }
  return (estado2 << 8) | estado1;
}

#endif